package Java.queue;

import java.io.Serializable;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;

public class MyPriorityQueue<E> extends AbstractQueue<E> implements Serializable {
    private static final long serialVersionUID = -5562353145249058369L;

    //初始数组容量
    private static final int DEFAULT_INITIAL_CAPACITY = 11;
    //最大数组长度（考虑到vm头部放入额外的信息）
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    //自定义比较器或者传入
    private final Comparator<? super E> comparator;
    //用数组存放元素
    transient Object[] queue;
    //当前队列结构修改次数
    transient int modCount = 0;
    //队列元素数量
    private int size = 0;

    public MyPriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

    public MyPriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
        //判断初始值
        if (initialCapacity < 1) {
            throw new IllegalArgumentException();
        }
        //初始化数组
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

    @Override

    public Iterator<E> iterator() {
        return null;
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean offer(E e) {
        //不能添加null元素
        if (e == null) {
            throw new NullPointerException();
        }
        //队列修改次数
        modCount++;
        int i = size;
        if (i > queue.length) {
            //扩容
            grow(i + 1);
        }
        size = i + 1;
        if (i == 0) {
            //传根节点
            queue[0] = e;
        } else {
            //计算插入的位置
            siftUp(i, e);
        }
        return true;
    }

    private void siftUp(int k, E x) {
        //判断是否使用比较器
        if (comparator != null) {
            siftUpUsingCompator(k, x);
        } else {
            siftUpComparable(k, x);
        }

    }

    /**
     * 从k指定的位置开始，将x逐层与当前点的parent进行比较并交换，直到满足x >= queue[parent]为止。注意这里的比较可以是元素的自然顺序，也可以是依靠比较器的顺序。
     */
    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0) {
                break;
            }
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;

    }

    private void siftUpUsingCompator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0) {
                break;
            }
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }

    private void grow(int minCapacity) {
        int oldCapacity = queue.length;
        //如果<64 就每次加二 否则就大一倍
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                (oldCapacity + 2) :
                (oldCapacity >> 1));
        //判断是否越界
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);

    }

    @Override
    public E poll() {
        if (size == 0) {
            return null;
        }
        int s = --size;
        modCount++;
        E result = (E) queue[0];
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);
        return result;
    }

    private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

    /**
     * 重点是siftDown(int k, E x)方法，该方法的作用是从k指定的位置开始，将x逐层向下与当前点的左右孩子中较小的那个交换，直到x小于或等于左右孩子中的任何一个为止。
     *
     * @param k
     * @param x
     */
    private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        int half = size >>> 1;        // loop while a non-leaf
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                    ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }

    private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                    comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }

    @Override
    public E peek() {
        return (size == 0) ? null : (E) queue[0];
    }

    boolean removeEq(Object o) {
        for (int i = 0; i < size; i++) {
            if (o == queue[i]) {
                removeAt(i);
                return true;
            }
        }
        return false;
    }


    private E removeAt(int i) {
        // assert i >= 0 && i < size;
        modCount++;
        int s = --size;
        if (s == i)
            //如果是最后一个元素，直接删除
            queue[i] = null;
        else {
            E moved = (E) queue[s];
            queue[s] = null;
            siftDown(i, moved);
            if (queue[i] == moved) {
                siftUp(i, moved);
                if (queue[i] != moved)
                    return moved;
            }
        }
        return null;
    }
}
